/**
 * 访问者模式
 */
//  表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。
//  准备好各种食物的餐厅
class Restaurant {
    private lobster = 'lobster';
    private watermelon = 'watermelon';
    private steak = 'steak';
    private banana = 'banana';
    welcome(visitor: IVisitor) {
        visitor.chooseLobster(this.lobster);
        visitor.chooseWatermelon(this.watermelon);
        visitor.chooseSteak(this.steak);
        visitor.chooseBanana(this.banana);
    }
}
// 为顾客提供的接口
interface IVisitor {
    chooseLobster(lobster: string): void;

    chooseWatermelon(watermelon: string): void;

    chooseSteak(steak: string): void;

    chooseBanana(banana: string): void;
}
// 顾客Aurora
class Aurora implements IVisitor {
    chooseLobster(lobster: string) {
        console.log('Aurora gets a ' + lobster);
    }

    chooseWatermelon(watermelon: string) {
        console.log('Aurora gets a ' + watermelon);
    }

    chooseSteak(steak: string) {
        console.log("Aurora doesn't like " + steak);
    }

    chooseBanana(banana: string) {
        console.log("Aurora doesn't like " + banana);
    }
}

const restaurant = new Restaurant();
const aurora: IVisitor = new Aurora();
restaurant.welcome(aurora);
// Aurora 对每一种食物做出了自己的选择，这就是一个最简单的访问者模式，
// 它已经体现出了访问者模式的核心思想：将数据的结构和对数据的操作分离。

// 自助餐程序 2.0 版
// 写一半发现 js 没有类的方法的重载

// abstract class Food {
//     abstract name(): string;
// }

// // 龙虾
// class Lobster extends Food {
//     name() {
//         return 'lobster';
//     }
// }
// // 西瓜：
// class Watermelon extends Food {
//     name() {
//         return 'watermelon';
//     }
// }
// // 牛排：
// class Steak extends Food {
//     name() {
//         return 'steak';
//     }
// }
// // 香蕉：
// class Banana extends Food {
//     name() {
//         return 'banana';
//     }
// }
// class Aurora2 implements IVisitor2 {
//     chooseFood(lobster: Lobster) {
//         console.log('Aurora gets a ' + lobster.name());
//     }

//     chooseFood(watermelon: Watermelon) {
//         console.log('Aurora gets a ' + watermelon.name());
//     }

//     chooseFood(steak: Steak) {
//         console.log("Aurora doesn't like " + steak.name());
//     }

//     chooseFood(banana: Banana) {
//         console.log("Aurora doesn't like " + banana.name());
//     }
// }
// // IVisitor 接口对应修改为：
// interface IVisitor2 {
//     chooseFood(lobster: Lobster): void;

//     chooseFood(watermelon: Watermelon): void;

//     chooseFood(steak: Steak): void;

//     chooseFood(banana: Banana): void;
// }

// // 餐厅类修改如下：
// class Restaurant2 {
//     // 准备当天的食物
//     private prepareFoods() {
//         const foods = new Set<Food>();
//         // 简单模拟，每种食物添加 10 份
//         for (let i = 0; i < 10; i++) {
//             foods.add(new Lobster());
//             foods.add(new Watermelon());
//             foods.add(new Steak());
//             foods.add(new Banana());
//         }
//         return foods;
//     }
//     // 欢迎顾客来访
//     welcome(visitor: IVisitor2) {
//         // 获取当天的食物
//         const foods = this.prepareFoods();

//         // 将食物依次提供给顾客选择
//         foods.forEach(food => {
//             // 由于单分派机制，此处无法编译通过
//             visitor.chooseFood(food);
//         });
//     }
// }

// const restaurant2 = new Restaurant2();
// const aurora2: IVisitor2 = new Aurora2();
// restaurant2.welcome(aurora2);
